package cn.itamt.fx {
	import cn.itamt.fx.core.Effect;

	import com.greensock.TweenNano;

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;	

	/**
	 * @author itamt@qq.com
	 */
	public class WobbleEffect extends Effect {

		private var vertices : Vector.<Number>;
		private	var indices : Vector.<int>;
		private	var uvtData : Vector.<Number>;
		private var vertexs : Array;
		private var tVertexs : Array;
		private var SEGMENT : int = 5;
		private var IMG_W : int;
		private var IMG_H : int;
		private var sprite : Sprite;
		private var bmd : BitmapData;
		private var deltas : Array;

		private var _filters : Array;

		public function set filters(val : Array) : void {
			_filters = val;
			
			if(this.sprite) {
				this.sprite.filters = _filters;
			}
		}

		public function get filters() : Array {
			return _filters;
		}

		public function WobbleEffect(tg : DisplayObject) : void {
			super(tg);
			
			if(tg is Bitmap) {
				bmd = (tg as Bitmap).bitmapData.clone();
			} else {
				_filters = tg.filters;
				tg.filters = null;
				bmd = snap(tg);
				tg.filters = _filters;
			}
			IMG_W = bmd.width;			IMG_H = bmd.height;
		}

		private var _visible : Boolean = true;

		public function set visible(val : Boolean) : void {
			_visible = val;
			if(this.sprite) {
				this.sprite.visible = _visible;
			}
		}

		public function get x() : Number {
			return tVertexs[0][0].x;
		}

		public function get y() : Number {
			return tVertexs[0][0].y;
		}

		/**
		 * 开始使用效果.
		 */
		override public function apply() : void {
			vertices = new Vector.<Number>();
			indices = new Vector.<int>();
			uvtData = new Vector.<Number>();
			vertexs = [];
			tVertexs = [];
			
			sprite = new Sprite();
			sprite.mouseChildren = sprite.mouseEnabled = false;
			sprite.visible = _visible;
			sprite.filters = _filters;
			stage.addChild(sprite);
			var pt : Point = _target.localToGlobal(new Point());
			
			var indStep : int;
			for (var xx : int = 0;xx <= SEGMENT; xx++) {
				vertexs[xx] = [];
				tVertexs[xx] = [];
				for (var yy : int = 0;yy <= SEGMENT; yy++) {
					vertexs[xx][yy] = new Point(pt.x + xx * IMG_W / SEGMENT, pt.y + yy * IMG_H / SEGMENT);//[xx * IMG_W / SEGMENT, yy * IMG_H/SEGMENT];
					tVertexs[xx][yy] = new Point(pt.x + xx * IMG_W / SEGMENT, pt.y + yy * IMG_H / SEGMENT);//[xx * IMG_W / SEGMENT, yy * IMG_H/SEGMENT];

					if(xx < SEGMENT && yy < SEGMENT) {
						uvtData.push(xx / SEGMENT, yy / SEGMENT, (xx + 1) / SEGMENT, yy / SEGMENT, (xx + 1) / SEGMENT, (yy + 1) / SEGMENT, xx / SEGMENT, (yy + 1) / SEGMENT);
						indices.push(indStep, indStep + 1, indStep + 3, indStep + 1, indStep + 2, indStep + 3);
						indStep += 4;
					}
				}
			}
			
			draw();
			
//			sprite.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
		}

		private var rpt : Point = new Point;

		public function onDown(evt : MouseEvent) : void {
			//			stage.addEventListener(MouseEvent.MOUSE_UP, onUp);

			rpt.x = evt.stageX;
			rpt.y = evt.stageY;
			
			deltas = [];
			for (var xx : int = 0;xx <= SEGMENT; xx++) {
				deltas[xx] = [];
				for (var yy : int = 0;yy <= SEGMENT; yy++) {
					deltas[xx][yy] = [tVertexs[xx][yy].x - rpt.x, tVertexs[xx][yy].y - rpt.y];
				}
			}
			
			stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
			if(completeCallTween)completeCallTween.kill();
		}

		private var tpt : Point = new Point;

		public function onUp(evt : MouseEvent) : void {
			//			stage.removeEventListener(MouseEvent.MOUSE_UP, onUp);

			tpt.x = evt.stageX;
			tpt.y = evt.stageY;
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMove);
			
			move();
			
			completeCallTween = TweenNano.delayedCall(maxDelay, onTweenFinish);
		}

		private var completeCallTween : TweenNano;

		public function onMove(evt : MouseEvent) : void {
			tpt.x = evt.stageX;
			tpt.y = evt.stageY;
			
			move();
		}

		private function onTweenFinish() : void {
			dispatchEvent(new Event(Event.COMPLETE));
		}

		private var maxDelay : Number = 0;

		private function move() : void {
			var xx : int, yy : int, delay : Number = 0;
			
			for (xx = 0;xx <= SEGMENT; xx++) {
				for (yy = 0;yy <= SEGMENT; yy++) {
					tVertexs[xx][yy].x = tpt.x + deltas[xx][yy][0];
					tVertexs[xx][yy].y = tpt.y + deltas[xx][yy][1];
					
					delay = Math.sqrt(deltas[xx][yy][0] * deltas[xx][yy][0] + deltas[xx][yy][1] * deltas[xx][yy][1]) / 400;
					
					TweenNano.to(vertexs[xx][yy], delay / 2, {onUpdate:draw, delay:delay / 50, x:tVertexs[xx][yy].x, y:tVertexs[xx][yy].y});
					
					maxDelay = Math.max(delay, maxDelay);
				}
			}
		}

		private function draw(e : Event = null) : void {
			if(vertexs == null)return;
			vertices = new Vector.<Number>();
			for(var xx : int = 0;xx < SEGMENT; xx++) {
				for(var yy : int = 0;yy < SEGMENT; yy++) {
					vertices.push(vertexs[xx][yy].x, vertexs[xx][yy].y, vertexs[xx + 1][yy].x, vertexs[xx + 1][yy].y, vertexs[xx + 1][yy + 1].x, vertexs[xx + 1][yy + 1].y, vertexs[xx][yy + 1].x, vertexs[xx][yy + 1].y);
				}
			}
			
			var g : Graphics = sprite.graphics;
			g.clear();
			//			g.lineStyle(1);
			g.beginBitmapFill(bmd);
			g.drawTriangles(vertices, indices, uvtData);
			g.endFill();
		}

		public static function snap(dp : DisplayObject) : BitmapData {
			var bmd : BitmapData;
			var bounds : Rectangle = dp.getBounds(dp);
			bmd = new BitmapData(bounds.width, bounds.height, true, 0x00ff0000);
			bmd.draw(dp, new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y));
			return bmd;
		}

		override public function dispose() : void {
			var xx : int, yy : int;
			for (xx = 0;xx <= SEGMENT; xx++) {
				for (yy = 0;yy <= SEGMENT; yy++) {
					TweenNano.killTweensOf(tVertexs[xx][yy]);
				}
			}
			
			vertices = null;
			indices = null;
			uvtData = null;
			vertexs = null;
			tVertexs = null;
			deltas = null;
			bmd.dispose();
			
			if(sprite) {
				if(sprite.stage) {
					sprite.parent.removeChild(sprite);
				}
			}
			
			sprite = null;
		}
	}
}
